/*
 * Copyright [2010] [GP Software]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SqlUtil.java | Created on April 26, 2010
 */
package org.gp.gpetl.util;

import org.apache.commons.lang.StringUtils;

import java.util.Map;

/**
 * Helper class that constructs the sql strings
 *
 * @author Paul Augustine C. Mendoza
 * @since 1.0
 */
public class SqlUtil {

    /**
     * Constructs the insert query string
     *
     * @param headers   the file headers
     * @param tableName the table name
     * @return the query string
     */
    public static String getSqlInsertString(String[] headers,
                                            String tableName) {
        if ((headers == null) || (headers.length == 0)) {
            throw new IllegalArgumentException(
                    "Table headers cannot be empty or null.");
        }
        if (StringUtils.isBlank(tableName)) {
            throw new IllegalArgumentException(
                    "Table name cannot be empty or null.");
        }

        StringBuffer query =
                new StringBuffer("INSERT INTO " + tableName.toUpperCase());
        appendColumnsList(query, headers);
        query.append("VALUES");
        appendParamsList(query, headers.length);
        return query.toString();
    }

    /**
     * Gets the data types
     *
     * @param headers    the column headers
     * @param columnsMap the columns map
     * @return the data types array
     */
    public static Object[] getParameters(String[] headers,
                                         Map<String, String> columnsMap,
                                         String[] data) {
        if (!hasValidParameters(headers, columnsMap, data)) {
            throw new IllegalArgumentException("Invalid parameters detected.");
        }
        Object[] parameters = new Object[headers.length];
        for (int i = 0; i < headers.length; i++) {
            String type = columnsMap.get(headers[i]);
            parameters[i] = getParameter(data[i], type);
        }
        return parameters;
    }

    /**
     * Checks for valid parameters
     *
     * @param headers    the headers
     * @param columnsMap the columns map
     * @param data       the data
     * @return true if valid
     */
    private static boolean hasValidParameters(String[] headers,
                                              Map<String, String> columnsMap,
                                              String[] data) {
        // Check nullity
        if ((headers == null) || (columnsMap == null) || (data == null)) {
            return false;
        }
        // Check lenths
        if (headers.length != data.length) {
            return false;
        }
        return true;
    }

    /**
     * Gets the parameter
     * <p/>
     * <p/>
     * Supports only the following data types <ul> <li>java.lang.String</li>
     * <li>java.lang.Object</li> <li>java.lang.Integer</li>
     * <li>java.lang.Double</li> <li>java.lang.Float</li> </ul>
     *
     * @param data the data value
     * @param type the data type
     * @return the parameter
     */
    private static Object getParameter(String data, String type) {
        Object parameter = data;
        if (type.equalsIgnoreCase("java.lang.Integer")) {
            parameter = Integer.parseInt(data);
        } else if (type.equalsIgnoreCase("java.lang.Float")) {
            parameter = Float.parseFloat(data);
        } else if (type.equalsIgnoreCase("java.lang.Double")) {
            parameter = Double.parseDouble(data);
        }
        return parameter;
    }

    /**
     * Appends the query columns list
     *
     * @param query the query
     */
    private static void appendColumnsList(StringBuffer query,
                                          String[] headers) {
        query.append(" (");
        for (int i = 0; i < headers.length; i++) {
            query.append(headers[i].toUpperCase());
            if (i < (headers.length - 1)) {
                query.append(",");
            }
        }
        query.append(") ");
    }

    /**
     * Appends the query parameters list
     *
     * @param query the query
     */
    private static void appendParamsList(StringBuffer query, int length) {
        query.append(" (");
        for (int i = 0; i < length; i++) {
            query.append("?");
            if (i < (length - 1)) {
                query.append(",");
            }
        }
        query.append(")");
    }

}
